
#ifndef __GLOVAR__
#define __GLOVAR__ 1

#include "glodef.h"

#define STRUCT_FLAGS                                                                      \
    struct f3_flags_t {                                                                   \
        unsigned int advection     : 3;                                                   \
                  /* 0 - Stokes, 1 - explicit, 2 - semi-implicit, 3 - characteristics */  \
                  /* 4 - Runge_Kutta 45 */                                                \
        unsigned int adj_advection : 3;                                                   \
        unsigned int time_order    : 2;   /* 0-3 unused for now */                        \
        unsigned int transfer      : 2;   /* 0 == interpolation, 1 == taylor */           \
        unsigned int moving_grid   : 1;   /* 0 == FALSE, 1 == TRUE */                     \
        unsigned int stationary    : 1;   /* are we solving lid-driven-cavity? */         \
        unsigned int convergence   : 1;   /* are we solving a convergence test? */        \
        unsigned int conv_adjoint  : 1;   /* are we solving a convergence test  */        \
        unsigned int periodic      : 3;                                                   \
        unsigned int need_adjoint  : 1;                                                   \
        unsigned int solver        : 2;   /* 0 - consistent splitting                     \
                                       * 1 - rotational inctemental pressure-correction   \
                                       */                                                 \
        unsigned int use_ale       : 1;                                                   \
        unsigned int shape_opt     : 3; /* leave some room */                             \
    }

#ifdef __F3_PARSER_Y__

extern STRUCT_FLAGS flags;
extern double Re;
extern double alpha;
extern double beta;

#else  /* __F3_PARSER_Y__ */

#include "grid3d.h"
// #include "alegrid.h"
#include "fe.h"
#include "fe_matr.h"
#include "g3d_mesq.h"

/* descriptive values of flags.advection */
enum {
    adv_none = 0, adv_explicit, adv_semi, adv_char, adv_rk45
};

/* descriptive values of flags.shape_opt */
enum {
    opt_noopt = 0, opt_pit, opt_armijo, opt_custom
};
/* descriptive values of flags.solver */
enum {
    solver_cs = 0, solver_pc
};

/* descriptive values of flags.periodic */
enum {
    per_no = 0, per_march, per_adjoint, per_armijo, per_broyden, per_lbfgs
};
extern const unsigned int per_default;
extern const char * const periodic_str[6];

/************ The Flags *******************************/
extern STRUCT_FLAGS flags;

enum {
    transfer_none = 0, transfer_taylor, transfer_interpolation
};

/************ The Physical Parameters *****************/
extern double Re; /* Reynolds number */
extern double Fr; /* Froude number (gravity) */
#define GetMu(T)    1
#define GetRho(T)   1

#ifdef	__cplusplus
extern "C" {
#endif

static inline double GetRe(void) {
    return Re;
}

static inline double GetFr(void) {
    return Fr;
}

#ifdef	__cplusplus
}
#endif


/************ Integration in time **********************/
#ifdef	__cplusplus
extern "C" {
#endif

void get_coefs(unsigned advection, double *mass_coef, double *stif_coef, double *advm_coef);

#ifdef	__cplusplus
}
#endif


/************ The Time Parameters **********************/
extern int total_ti, curr_ti;
extern double TStep, StopTime;
#define TIME ((double)(curr_ti*TStep))

#ifdef	__cplusplus
extern "C" {
#endif

void SetTimeParams(double start, double stop, double step);

#ifdef	__cplusplus
}
#endif

/************ The Grid *********************************/
// extern alegrid_t *alegrid;
extern grid3d_t *grid;
extern mesq_handle mesquite;
extern node_t *adv_nodes; /* only used if advection is set to adv_char */

/* heart geometry */
// extern unsigned on_ival, on_oval, on_memb, on_pipe, on_chbr;

/************ The solution vectors *********************/
extern vector u, u0, u1, adv_u;
extern scalar p, p0, p1, phi;

/************ The adjoint solution *********************/
extern vector v, v0, v1;
extern scalar q, q0, q1, qhi;

#ifdef	__cplusplus
extern "C" {
#endif

void alloc_glovar(unsigned elemU, unsigned elemP);
void clean_glovecs(void);
void free_glovar(void);

/************ some matrices ****************************/
extern fe_matr_p massP, massU;

/************ The Functions ****************************/
extern void (*exct_vel)(double, const double *, double *);
extern void (*exct_prs)(double, const double *, double *);

extern void (*init_vel)(double, const double *, double *);
extern void (*init_prs)(double, const double *, double *);
extern void (*srce_trm)(double, const double *, double *);

extern void (*adj_exct_vel)(double, const double *, double *);
extern void (*adj_exct_prs)(double, const double *, double *);

extern void (*adj_finl_vel)(double, const double *, double *);
extern void (*adj_finl_prs)(double, const double *, double *);
extern void (*adj_srce_trm)(double, const double *, double *);


/* In the following 2 routines:
    if the xxx_str is valid, then the corresponding function variable is
        assigned to a routine that parses and evaluates the string;
    if the xxx_str is NULL, then the corresponding function variable
        remains unchanged;
    if the xxx_str is not NULL, but begins with a '\0' then any previousely
        allocated string is released and the function variable is set to NULL
   NOTE: If a function variable other than exct_xxx is NULL, it is effectively
   treated as the 0 constant function (scalar or vector respectively).
   If both exct_xxx variable are NULL, then it is assumed that the exact
   solution is unknown (e.g. lid-driven-cavity).  If one of exct_xxx is NULL
   and the other one isn't, then it is assumed that the exact solution is known
   and the NULL variable is effectively treated as constant 0.
 */

void SetFuncStrings(const char *init_vel_str,
        const char *init_prs_str, const char *srce_trm_str);
void SetExctStrings(const char *exct_vel_str, const char *exct_prs_str);
void SetAdjFuncStrings(const char *adj_init_vel_str,
        const char *adj_init_prs_str, const char *adj_srce_trm_str);
void SetAdjExctStrings(const char *adj_exct_vel_str, const char *adj_exct_prs_str);


extern void (*bdry_vel)(unsigned on_bdry, double T, const double *Pt, double *V);
extern void (*adj_bdry_vel)(unsigned on_bdry, double T, const double *Pt, double *V);

extern void (*shgrd_vel)(unsigned on_bdry, double T, const double *Pt, double *V);

/* In the following:
 *    SetBdryNum sets the number of pieces of the boundary
 *    SetBdryFuncString assigns a string to be evaluated as boundary
 *          condition on the specified piece of the boundary.  The same rules
 *          as above apply
 *    SetBdryFuncRoutine assigns a routine to be called when evaluating the
 *          boundary condition on this chunk of the boundary.
 */
/* void SetBdryNum(unsigned NB); */
void SetBdryFuncString(unsigned bdry_no, const char *bdry_vel_str);
void SetBdryFuncRoutine(unsigned bdry_no, field3d *this_bdry_vel);
void SetAdjBdryFuncString(unsigned bdry_no, const char *adj_bdry_vel_str);
void SetAdjBdryFuncRoutine(unsigned bdry_no, field3d *adj_this_bdry_vel);

void SetShGrdBdryFuncString(unsigned bdry_no, const char *shape_grad_str);
void SetShGrdBdryFuncRoutine(unsigned bdry_no, field3d *shape_grad_vel);

#ifdef	__cplusplus
}
#endif


#endif /* __F3_PARSER_Y__ */

#endif /* __GLOVAR__ */
